﻿namespace Stopwatch.Core
{
    using System;
    using System.Threading;

    public class StopTimer
    {
        DateTime pausedDateTime;

        public DateTime StartDateTime { get; private set; }

        const int PERIOD = 10;

        Timer timer;

        public Time beginTime { get; private set; }

        public Time time { get; private set; }

        public Time WarningTime { get; set; }

        public int Hour { get { return time.Hours; } }

        public int Minute { get { return time.Minutes; } }

        public int Second { get { return time.Seconds; } }

        public Status Status { get; private set; }

        public StopTimer(int hour, int minute, int second)
        {
            beginTime = new Time(hour, minute, second);
            time = beginTime;
            WarningTime = new Time(seconds: 5);
            timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
        }

        public void Start()
        {
            if (beginTime <= Time.Zero)
            {
                return;
            }

            if (Status == Status.Paused)
            {
                StartDateTime += (DateTime.Now - pausedDateTime);
            }
            else
            {
                StartDateTime = DateTime.Now;
            }

            timer.Change(PERIOD, PERIOD);
            Status = Status.Started;
        }

        public void Pause()
        {
            timer.Change(Timeout.Infinite, Timeout.Infinite);
            pausedDateTime = DateTime.Now;
            Status = Status.Paused;

            if (Paused != null)
            {
                Paused(this, EventArgs.Empty);
            }
        }

        public void Reset()
        {
            Stop();
            time = Time.Zero;
        }

        void Stop()
        {
            timer.Change(Timeout.Infinite, Timeout.Infinite);
            Status = Status.Stoped;

            if (Stoped != null)
            {
                Stoped(this, EventArgs.Empty);
            }
            Status = Status.Ready;
        }

        private void TimerCallback(object state)
        {
            var timeSpan = DateTime.Now - StartDateTime;
            time = beginTime - new Time(timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);

            if (Tick != null)
            {
                Tick(this, EventArgs.Empty);
            }

            if (Warning != null && time <= WarningTime)
            {
                Warning(this, EventArgs.Empty);
            }

            if (time <= Time.Zero)
            {
                Stop();
            }
        }

        public event EventHandler Paused;
        public event EventHandler Stoped;
        public event EventHandler Tick;

        public event EventHandler Warning;

        public void Dispose()
        {
            if (timer != null)
            {
                timer.Dispose();
                timer = null;
            }
        }
    }
}
